﻿/*
Copyright (c) 2012 <a href="http://www.gutgames.com">James Craig</a>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/

#region Usings
using System;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using Utilities.DataTypes.Formatters;
using System.Data.Entity.Design.PluralizationServices;
using System.Globalization;
#endregion

namespace Utilities.DataTypes.ExtensionMethods
{
    /// <summary>
    /// String extensions
    /// </summary>
    public static class StringExtensions
    {
        #region 方法

        #region 保留字母

        /// <summary>
        /// 只保留字母字符
        /// </summary>
        /// <param name="Input">输入的字符串</param>
        /// <returns>只能包含字母字符的字符串</returns>
        public static string AlphaCharactersOnly(this string Input)
        {
            return Input.KeepFilterText("[a-zA-Z]");
        }

        #endregion

        #region 保留字母和数字

        /// <summary>
        /// 只保留字母和数字字符
        /// </summary>
        /// <param name="Input">输入的字符串</param>
        /// <returns>只能包含字母和数字字符的字符串</returns>
        public static string AlphaNumericOnly(this string Input)
        {
            return Input.KeepFilterText("[a-zA-Z0-9]");
        }

        #endregion

        #region 居中

        /// <summary>
        /// Centers the input string (if it's longer than the length) and pads it using the padding string
        /// </summary>
        /// <param name="Input"></param>
        /// <param name="Length"></param>
        /// <param name="Padding"></param>
        /// <returns>居中的字符串</returns>
        public static string Center(this string Input,int Length,string Padding=" ")
        {
            if (Input.IsNullOrEmpty())
                Input = "";
            string Output = "";
            for (int x = 0; x < (Length - Input.Length) / 2; ++x)
            {
                Output += Padding[x % Padding.Length];
            }
            Output += Input;
            for (int x = 0; x < (Length - Input.Length) / 2; ++x)
            {
                Output += Padding[x % Padding.Length];
            }
            return Output;
        }

        #endregion

        #region 编码

        /// <summary>
        /// Converts a string to a string of another encoding
        /// </summary>
        /// <param name="Input">input string</param>
        /// <param name="OriginalEncodingUsing">The type of encoding the string is currently using (defaults to ASCII)</param>
        /// <param name="EncodingUsing">The type of encoding the string is converted into (defaults to UTF8)</param>
        /// <returns>string of the byte array</returns>
        public static string Encode(this string Input, Encoding OriginalEncodingUsing = null, Encoding EncodingUsing = null)
        {
            if (string.IsNullOrEmpty(Input))
                return "";
            OriginalEncodingUsing = OriginalEncodingUsing.NullCheck(new ASCIIEncoding());
            EncodingUsing = EncodingUsing.NullCheck(new UTF8Encoding());
            return Encoding.Convert(OriginalEncodingUsing, EncodingUsing, Input.ToByteArray(OriginalEncodingUsing))
                           .ToEncodedString(EncodingUsing);
        }

        #endregion

        #region 将制表符扩展

        /// <summary>
        /// 扩展选项卡，并将它们替换为空格
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <param name="TabSize">Number of spaces</param>
        /// <returns>The input string, with the tabs replaced with spaces</returns>
        public static string ExpandTabs(this string Input, int TabSize = 4)
        {
            if (Input.IsNullOrEmpty())
                return Input;
            string Spaces = "";
            for (int x = 0; x < TabSize; ++x)
                Spaces += " ";
            return Input.Replace("\t", Spaces);
        }

        #endregion

        #region 筛选出的文本

        /// <summary>
        /// Removes the filter text from the input.
        /// </summary>
        /// <param name="Input">Input text</param>
        /// <param name="Filter">Regex expression of text to filter out</param>
        /// <returns>The input text minus the filter text.</returns>
        public static string FilterOutText(this string Input, string Filter)
        {
            if (string.IsNullOrEmpty(Input))
                return "";
            return string.IsNullOrEmpty(Filter) ? Input : new Regex(Filter).Replace(Input, "");
        }

        #endregion

        #region FormatString

        /// <summary>
        /// Formats a string based on a format string passed in:
        /// # = digits
        /// @ = alpha characters
        /// \ = escape char
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <param name="Format">Format of the output string</param>
        /// <returns>The formatted string</returns>
        public static string FormatString(this string Input, string Format)
        {
            return new GenericStringFormatter().Format(Input, Format);
        }

        #endregion

        #region FromBase64

        /// <summary>
        /// 转换为基地 64 基于传递中的编码的字符串
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <param name="EncodingUsing">The type of encoding the string is using (defaults to UTF8)</param>
        /// <returns>string in the encoding format</returns>
        public static string FromBase64(this string Input, Encoding EncodingUsing)
        {
            if (string.IsNullOrEmpty(Input))
                return "";
            byte[] TempArray = Convert.FromBase64String(Input);
            return EncodingUsing.NullCheck(new UTF8Encoding()).GetString(TempArray);
        }

        /// <summary>
        /// Converts base 64 string to a byte array
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <returns>A byte array equivalent of the base 64 string</returns>
        public static byte[] FromBase64(this string Input)
        {
            return string.IsNullOrEmpty(Input) ? new byte[0] : Convert.FromBase64String(Input);
        }

        #endregion

        #region 是否是 unicode

        /// <summary>
        /// 确定字符串是否是 unicode
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <returns>True if it's unicode, false otherwise</returns>
        public static bool IsUnicode(this string Input)
        {
            return string.IsNullOrEmpty(Input) ? true : Regex.Replace(Input, @"[^\u0000-\u007F]", "") != Input;
        }

        #endregion

        #region 保留过滤文本

        /// <summary>
        /// 移除不是从输入正则表达式文本中的一切。
        /// </summary>
        /// <param name="Input">输入的文本</param>
        /// <param name="Filter">要保留文本的正则表达式</param>
        /// <returns>减去一切都不在筛选器文本输入的文本。</returns>
        public static string KeepFilterText(this string Input, string Filter)
        {
            if (string.IsNullOrEmpty(Input) || string.IsNullOrEmpty(Filter))
                return "";
            Regex TempRegex = new Regex(Filter);
            MatchCollection Collection = TempRegex.Matches(Input);
            StringBuilder Builder = new StringBuilder();
            foreach (Match Match in Collection)
                Builder.Append(Match.Value);
            return Builder.ToString();
        }

        #endregion

        #region 左截取

        /// <summary>
        /// 获取字符串，从左边截取
        /// </summary>
        /// <param name="Input">输入的字符串</param>
        /// <param name="Length">要返回的字符数</param>
        /// <returns>生成的字符串</returns>
        public static string Left(this string Input, int Length)
        {
            return string.IsNullOrEmpty(Input) ? "" : Input.Substring(0, Input.Length > Length ? Length : Input.Length);
        }

        #endregion

        #region MaskLeft

        /// <summary>
        /// 掩码字符左侧终止于一个特定的字符
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <param name="EndPosition">End position (counting from the left)</param>
        /// <param name="Mask">Mask character to use</param>
        /// <returns>The masked string</returns>
        public static string MaskLeft(this string Input, int EndPosition = 4, char Mask = '#')
        {
            string Appending = "";
            for (int x = 0; x < EndPosition; ++x)
                Appending += Mask;
            return Appending + Input.Remove(0, EndPosition);
        }

        #endregion

        #region MaskRight

        /// <summary>
        /// Masks characters to the right starting at a specific character
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <param name="StartPosition">Start position (counting from the left)</param>
        /// <param name="Mask">Mask character to use</param>
        /// <returns>The masked string</returns>
        public static string MaskRight(this string Input, int StartPosition = 4, char Mask = '#')
        {
            if (StartPosition > Input.Length)
                return Input;
            string Appending = "";
            for (int x = 0; x < Input.Length - StartPosition; ++x)
                Appending += Mask;
            return Input.Remove(StartPosition) + Appending;
        }

        #endregion

        #region 下一个序列

        /// <summary>
        /// 字符串生成一系列有用的功能。所以成为 b，b 成为 c 等。 
        /// 号和击球的最大字符后, 转到两个字符 （所以 ~ 成为 aa，然后 ab、 ac、 等）。
        /// </summary>
        /// <param name="Sequence">Current sequence</param>
        /// <returns>The next item in the sequence</returns>
        public static string NextSequence(this string Sequence, char Min = ' ', char Max = '~')
        {
            byte[] Values = Sequence.ToByteArray();
            byte MinValue = (byte)Min;
            byte MaxValue = (byte)Max;
            byte Remainder = 1;
            for (int x = Sequence.Length - 1; x >= 0; --x)
            {
                Values[x] += Remainder;
                Remainder = 0;
                if (Values[x] > MaxValue)
                {
                    Remainder = 1;
                    Values[x] = (byte)Min;
                }
                else
                    break;
            }
            if (Remainder == 1)
                return Min + Values.ToEncodedString();
            return Values.ToEncodedString();
        }

        #endregion

        #region 只有数字

        /// <summary>
        /// Keeps only numeric characters
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <param name="KeepNumericPunctuation">Determines if decimal places should be kept</param>
        /// <returns>the string only containing numeric characters</returns>
        public static string NumericOnly(this string Input, bool KeepNumericPunctuation = true)
        {
            return KeepNumericPunctuation ? Input.KeepFilterText(@"[0-9\.]") : Input.KeepFilterText("[0-9]");
        }

        #endregion

        #region 发生的次数

        /// <summary>
        /// returns the number of times a string occurs within the text
        /// </summary>
        /// <param name="Input">input text</param>
        /// <param name="Match">The string to match (can be regex)</param>
        /// <returns>The number of times the string occurs</returns>
        public static int NumberTimesOccurs(this string Input, string Match)
        {
            return string.IsNullOrEmpty(Input) ? 0 : new Regex(Match).Matches(Input).Count;
        }

        #endregion

        #region 以复数形式表示

        /// <summary>
        /// Pluralizes a word
        /// </summary>
        /// <param name="Word">Word to pluralize</param>
        /// <param name="Culture">Culture info used to pluralize the word (defaults to current culture)</param>
        /// <returns>The word pluralized</returns>
        public static string Pluralize(this string Word, CultureInfo Culture = null)
        {
            if (Word.IsNullOrEmpty())
                return "";
            Culture = Culture.NullCheck(CultureInfo.CurrentCulture);
            return PluralizationService.CreateService(Culture).Pluralize(Word);
        }

        #endregion

        #region 正则表达式格式

        /// <summary>
        /// Uses a regex to format the input string
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <param name="Format">Regex string used to</param>
        /// <param name="OutputFormat">Output format</param>
        /// <param name="Options">Regex options</param>
        /// <returns>The input string formatted by using the regex string</returns>
        public static string RegexFormat(this string Input, string Format, string OutputFormat, RegexOptions Options = RegexOptions.None)
        {
            Input.ThrowIfNullOrEmpty("Input");
            return Regex.Replace(Input, Format, OutputFormat, Options);
        }

        #endregion

        #region 反向

        /// <summary>
        /// Reverses a string
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <returns>The reverse of the input string</returns>
        public static string Reverse(this string Input)
        {
            return new string(Input.Reverse<char>().ToArray());
        }

        #endregion

        #region 右

        /// <summary>
        /// Gets the last x number of characters from the right hand side
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <param name="Length">x number of characters to return</param>
        /// <returns>The resulting string</returns>
        public static string Right(this string Input, int Length)
        {
            if (string.IsNullOrEmpty(Input))
                return "";
            Length = Input.Length > Length ? Length : Input.Length;
            return Input.Substring(Input.Length - Length, Length);
        }

        #endregion

        #region 单数形式

        /// <summary>
        /// 单数形式的单词
        /// </summary>
        /// <param name="Word">Word to singularize</param>
        /// <param name="Culture">Culture info used to singularize the word (defaults to current culture)</param>
        /// <returns>The word singularized</returns>
        public static string Singularize(this string Word, CultureInfo Culture = null)
        {
            if (Word.IsNullOrEmpty())
                return "";
            Culture = Culture.NullCheck(CultureInfo.CurrentCulture);
            return PluralizationService.CreateService(Culture).Singularize(Word);
        }

        #endregion

        #region 从左边删除

        /// <summary>
        /// Strips out any of the characters specified starting on the left side of the input string (stops when a character not in the list is found)
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <param name="Characters">Characters to string (defaults to a space)</param>
        /// <returns>The Input string with specified characters stripped out</returns>
        public static string StripLeft(this string Input, string Characters = " ")
        {
            if (Input.IsNullOrEmpty())
                return Input;
            if (Characters.IsNullOrEmpty())
                return Input;
            return Input.SkipWhile(x => Characters.Contains(x)).ToString(x => x.ToString(), "");
        }

        #endregion

        #region 从右边删除

        /// <summary>
        /// 带出的任何字符指定开始在右侧的输入字符串 （发现不在列表中的字符时停止）
        /// </summary>
        /// <param name="Input">输入的字符串</param>
        /// <param name="Characters">字符的字符串 （默认为一个空格）</param>
        /// <returns>与指定的字符的输入字符串剥离</returns>
        public static string StripRight(this string Input, string Characters = " ")
        {
            if (Input.IsNullOrEmpty())
                return Input;
            if (Characters.IsNullOrEmpty())
                return Input;
            int Position = Input.Length - 1;
            for (int x = Input.Length - 1; x >= 0; --x)
            {
                if (!Characters.Contains(Input[x]))
                {
                    Position = x + 1;
                    break;
                }
            }
            return Input.Left(Position);
        }

        #endregion

        #region ToBase64

        /// <summary>
        /// 将从指定的编码到 base 64 字符串转换
        /// </summary>
        /// <param name="Input">输入的字符串</param>
        /// <param name="OriginalEncodingUsing">编码字符串的类型使用 （默认为 UTF8）</param>
        /// <returns>Bas64 string</returns>
        public static string ToBase64(this string Input, Encoding OriginalEncodingUsing = null)
        {
            if (string.IsNullOrEmpty(Input))
                return "";
            byte[] TempArray = OriginalEncodingUsing.NullCheck(new UTF8Encoding()).GetBytes(Input);
            return Convert.ToBase64String(TempArray);
        }

        #endregion

        #region ToByteArray

        /// <summary>
        /// 将字符串转换为字节数组
        /// </summary>
        /// <param name="Input">input string</param>
        /// <param name="EncodingUsing">The type of encoding the string is using (defaults to UTF8)</param>
        /// <returns>the byte array representing the string</returns>
        public static byte[] ToByteArray(this string Input, Encoding EncodingUsing = null)
        {
            return string.IsNullOrEmpty(Input) ? null : EncodingUsing.NullCheck(new UTF8Encoding()).GetBytes(Input);
        }

        #endregion

        #region 第一个字符大写

        /// <summary>
        /// 输入字符串的第一个字符并使它变为大写
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <returns>String with the first character capitalized</returns>
        public static string ToFirstCharacterUpperCase(this string Input)
        {
            if (string.IsNullOrEmpty(Input))
                return "";
            char[] InputChars = Input.ToCharArray();
            for (int x = 0; x < InputChars.Length; ++x)
            {
                if (InputChars[x] != ' ' && InputChars[x] != '\t')
                {
                    InputChars[x] = char.ToUpper(InputChars[x]);
                    break;
                }
            }
            return new string(InputChars);
        }

        #endregion

        #region 对句大写

        /// <summary>
        /// 大写字符串内的每个句子
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <returns>String with each sentence capitalized</returns>
        public static string ToSentenceCapitalize(this string Input)
        {
            if (string.IsNullOrEmpty(Input))
                return "";
            string[] Seperator = { ".", "?", "!" };
            string[] InputStrings = Input.Split(Seperator, StringSplitOptions.None);
            for (int x = 0; x < InputStrings.Length; ++x)
            {
                if (!string.IsNullOrEmpty(InputStrings[x]))
                {
                    Regex TempRegex = new Regex(InputStrings[x]);
                    InputStrings[x] = InputStrings[x].ToFirstCharacterUpperCase();
                    Input = TempRegex.Replace(Input, InputStrings[x]);
                }
            }
            return Input;
        }

        #endregion

        #region 为词首字母大写

        /// <summary>
        /// 每个单词的首字母大写
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <returns>String with each word capitalized</returns>
        public static string ToTitleCase(this string Input)
        {
            if (string.IsNullOrEmpty(Input))
                return "";
            string[] Seperator = { " ", ".", "\t", System.Environment.NewLine, "!", "?" };
            string[] InputStrings = Input.Split(Seperator, StringSplitOptions.None);
            for (int x = 0; x < InputStrings.Length; ++x)
            {
                if (!string.IsNullOrEmpty(InputStrings[x])
                    && InputStrings[x].Length > 3)
                {
                    Regex TempRegex = new Regex(InputStrings[x].Replace(")", @"\)").Replace("(", @"\(").Replace("*", @"\*"));
                    InputStrings[x] = InputStrings[x].ToFirstCharacterUpperCase();
                    Input = TempRegex.Replace(Input, InputStrings[x]);
                }
            }
            return Input;
        }

        #endregion

        #endregion

        #region 整理
        /// <summary>
        /// 转换为int类型的数组
        /// </summary>
        /// <param name="Input">输入字符串</param>
        /// <param name="Separator">分隔符，默认‘,’</param>
        /// <returns></returns>
        public static int[] ToIntArray(this string Input, char Separator = ',')
        {
            return Array.ConvertAll<string, int>(Input.Split(Separator), s => int.Parse(s));
        } 
        #endregion
    }
}